﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Net;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Web;
using System.IO;

namespace Com.VikingErik.Mvc.ResumingDownloadsTests
{
    /// <summary>
    /// Summary description for UnitTest1
    /// </summary>
    [TestClass]
    public class WebRequestTesting
    {
        public WebRequestTesting()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion

        private HttpWebRequest CreateRequestForMediaFile()
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(@"http://localhost:1715/Home/Media/What%20is%20Creative%20Commons%20Wanna%20Work%20Together%20RG%20Remix.mp4");
            request.UserAgent = "Mozilla/4.0 (TestScripts)";

            return request;
        }

        private void PerformStandardChecks(HttpWebRequest request, HttpWebResponse response, long? start, long? end, long? expected, HttpStatusCode expectedStatusCode)
        {
            string requestedRange = request.Headers[HttpWorkerRequest.GetKnownRequestHeaderName(HttpWorkerRequest.HeaderRange)];
            string responseRange = response.Headers[HttpWorkerRequest.GetKnownResponseHeaderName(HttpWorkerRequest.HeaderContentRange)];

            Assert.AreEqual(expectedStatusCode, response.StatusCode);

            if (!string.IsNullOrWhiteSpace(requestedRange))
            {
                Assert.IsNotNull(responseRange, "Request contained a Range header but the response did not contain a Content Range header");
                Assert.AreNotEqual(string.Empty, responseRange, "Request contained a Range header but the response had an empty Content Range header");
            }

            if (!string.IsNullOrWhiteSpace(responseRange))
            {
                Assert.IsNotNull(requestedRange, "Response contained a Content Range header but there was no request for Range");
                Assert.AreNotEqual(string.Empty, requestedRange, "Response contained a Content Range header but the request for Range was empty");



                ContentRange contentRange = ContentRangeParser.ParseRange(responseRange);
                Assert.IsNotNull(contentRange, "Content Range in the response could not be properly parsed");

                if (start.HasValue)
                    Assert.AreEqual(start.Value, contentRange.StartIndex);

                if (end.HasValue)
                    Assert.AreEqual(end.Value, contentRange.EndIndex);


                using (Stream sr = response.GetResponseStream())
                {
                    long size = 0;
                    int count;
                    byte[] fileBytes = new byte[4096];
                    do
                    {
                        count = sr.Read(fileBytes, 0, fileBytes.Length);
                        size += count;
                    }
                    while (count > 0);

                    Assert.AreEqual((contentRange.EndIndex - contentRange.StartIndex + 1), size, "The result file was not the same size as the requested size");

                    if (expected.HasValue)
                        Assert.AreEqual(expected.Value, size);
                }
            }
              
        }


        [TestMethod]
        public void RequestStartEndRange()
        {
            long REQ_START = 0, REQ_END = 250;

            HttpWebRequest request = CreateRequestForMediaFile();
            request.AddRange(REQ_START, REQ_END);

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();

            PerformStandardChecks(request, response, REQ_START, REQ_END, null, HttpStatusCode.PartialContent);
               
        }

        [TestMethod]
        public void RequestOpenEndedRange()
        {
            long REQ_INDEX = 250;

            HttpWebRequest request = CreateRequestForMediaFile();
            request.AddRange(REQ_INDEX);

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();

            PerformStandardChecks(request, response, REQ_INDEX, null, null, HttpStatusCode.PartialContent);
        }

        [TestMethod]
        public void RequestOpenStartRange()
        {
            long REQ_INDEX = -250;

            HttpWebRequest request = CreateRequestForMediaFile();
            request.AddRange(REQ_INDEX);

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();

            PerformStandardChecks(request, response, null, null, Math.Abs(REQ_INDEX), HttpStatusCode.PartialContent);
            
        }

        [TestMethod]
        public void CompleteRequestViaRange()
        {
            var request = CreateRequestForMediaFile();
            request.AddRange(0);

            var response = (HttpWebResponse)request.GetResponse();

            PerformStandardChecks(request, response, 0, null, null, HttpStatusCode.PartialContent);
        }

        [TestMethod]
        public void NonRangedRequest()
        {
            var request = CreateRequestForMediaFile();
            var response = (HttpWebResponse)request.GetResponse();

            PerformStandardChecks(request, response, null, null, null, HttpStatusCode.OK);
        }


        [TestMethod]
        public void MultipartRange()
        {
            HttpWebRequest request = CreateRequestForMediaFile();
            request.AddRange(0, 50);
            request.AddRange(50, 55);
            request.AddRange(100, 200);

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();

            string requestedRange = request.Headers[HttpWorkerRequest.GetKnownRequestHeaderName(HttpWorkerRequest.HeaderRange)];
            string responseRange = response.Headers[HttpWorkerRequest.GetKnownResponseHeaderName(HttpWorkerRequest.HeaderContentRange)];

            string responseMessage = response.ContentType;
            Assert.AreEqual("multipart/byteranges; boundary=<q1w2e3r4t5y6u7i8o9p0>; charset=utf-8", responseMessage, "Response content type was not multipart as expected");
        }
    }
}
